﻿#region  Copyright (C) 2013 Unisys Corporation

// =============================================================================================
// All Rights Reserved. This work contains trade secrets and confidential material of UNISYS, 
// and its use or disclosure in whole or in part without explicit written permission of 
// UNISYS is prohibited. 
//  
// Product Name          :  Unisys e-Workflow and Imaging 8.2
// File Name             :  BDAdministrator.cs
// Authored By           :  Unisys Corporation
// =============================================================================================
//	Modified by                         Date            Version
// =============================================================================================
//	ronald.aguilar@cr.unisys.com      Jun 06, 2013    Initial Version
// =============================================================================================

#endregion
#region Using Region
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using Unisys.DuplicateCheck.Entity;
using Unisys.DuplicateCheck.Entity.Model;
using Unisys.DuplicateCheck.Data;
using Unisys.DuplicateCheck.Data.DataBase;
using Unisys.DuplicateCheck.Logic.Services;
#endregion

namespace Unisys.DuplicateCheck.Logic.BDAdministrator
{
    public class BDManager
    {
        private SqlDataReader duplicateList;
        private DuplicateService bussinessRules;

        public SqlDataReader DuplicateList( DuplicateService businessRules, DocClass docClass)
        {
            
            this.bussinessRules = businessRules;
        string query = "Select top " + Convert.ToInt32(Configuration.topQuery) +
       " ROW_NUMBER() OVER(PARTITION BY A.OBJECT_SERVER," + 
                             getFields(businessRules.getAllFields(docClass)) +
                             " ORDER BY A.OBJECT_SERVER,"+
                                        getFields(businessRules.getAllFields(docClass)) + 
                                      ",VENCE, A.OBJECT_ID) AS ORD_VENCE,"+
                                      "ROW_NUMBER() OVER(PARTITION BY A.OBJECT_SERVER," +
                                     getFields(businessRules.getAllFields(docClass)) +
                             " ORDER BY A.OBJECT_SERVER,"+
                             getFields(businessRules.getAllFields(docClass)) +	",OBJECT_ID) AS ORD_FECHA_REGISTRO," +
        " A.OBJECT_CLASS, A.OBJECT_SERVER, " +
         getFields(businessRules.getAllFields(docClass))+
        ",A.OBJECT_ID, A.OBJECT_NAME, A.OBJECT_TYPE,"+
        "A.VENCE, "+
        "CONVERT(DATE,DATEADD(day, CAST(substring(A.OBJECT_ID,3,3) AS int)-1,CONVERT(datetime,'20'+substring(A.OBJECT_ID,1,2)+'0101',112))) AS FECHA_REGISTRO,"+
        "Version_Workitem, Historico "+
   "From ATTRIBUTES A "+
   "WHERE A.OBJECT_CLASS In (" + businessRules.getDuplicateClasses(docClass) + ") " +
   " And Not Exists (Select 'x' From QUEUES Q Where Q.ID = A.OBJECT_ID)"+
    " And EXISTS (Select 'x' From ATTRIBUTES C "+
                 "Where C.OBJECT_SERVER = A.OBJECT_SERVER "+
                 getAllDuplicateFields(businessRules.getAllFields(docClass)) +
                   " And C.Historico IS NULL)"+
  " Order By A.OBJECT_SERVER," + 
            getFields(businessRules.getAllFields(docClass))+
            ",VENCE,"+
            "A.OBJECT_ID";

        Service.sendLog(query, Service.errorType.Information_Message);
            SqlDataClass dataClass = new SqlDataClass();
            Service.sendLog("Enviando query...", Service.errorType.Information_Message);
            duplicateList = dataClass.SQLRead(query);
            Service.sendLog("Query Enviado exitosamente y resultado retornado...", Service.errorType.Information_Message);

            return duplicateList;

        }

        public string getFields(List<string> list)
        {
            string result = "";
            string[] x= list.ToArray().Distinct().ToArray();
            foreach (string str in x)
            {
                result += " A." + str+",";
            }
            return result.Remove(result.Length - 1);

        }
       
        public bool processDocument(List<duplicateDocument> Documents/*SqlDataReader reader*/)
        {
            foreach (duplicateDocument document in Documents)
            {
                string ID = document.getIDValue();
                Service.sendLog("Procesando Documento con Object ID: [" + ID + "]", Service.errorType.Information_Message);

                #region Rejected
                bool isNotDuplicate = false;
                foreach (Rejected rejected in bussinessRules.RejectedClass)
                {
                    if (document.getValue("CLASS").Equals(rejected.Name))//si es la misma clase
                        if (document.getValue(rejected.FieldName).Equals(rejected.FieldValue))//documento rechazado
                        {
                            Service.sendLog("Documento con Object ID: [" + ID + "]  y Object_Class: [" + document.getValue("OBJECT_CLASS") + "]  fue considerado como RECHAZADO.", Service.errorType.Information_Message);

                            List<duplicateDocument> temp =new List<duplicateDocument>();
                            temp.Add(document);
                            versionDuplicates(temp, true);
                            isNotDuplicate = true;
                            Documents.Remove(document);
                            break;
                        }

                }

                if (isNotDuplicate)
                    continue;
                
                #endregion

                #region Inconsistencies

                Incosistence inconsistences = verifyInconsistencies(document, bussinessRules);
                if (inconsistences != null)
                {
                    Service.sendLog("Documento con Object ID: [" + ID + "]  y Object_Class: [" + document.getValue("OBJECT_CLASS") + "]  fue considerado como INCONSISTENCIA.", Service.errorType.Information_Message);

                    List<duplicateDocument> temp = new List<duplicateDocument>();
                    temp.Add(document);
                    versionDuplicates(temp, true);
                    Documents.Remove(document);
                    continue;
                }
               
                #endregion

                #region Exceptions
                DocClassExc exceptions = verifyException(document, bussinessRules);
                if (exceptions != null)
                {
                    Service.sendLog("Documento con Object ID: [" + ID + "]  y Object_Class: [" + document.getValue("OBJECT_CLASS") + "] fue considerado como EXCEPCION.", Service.errorType.Information_Message);

                    List<duplicateDocument> temp = new List<duplicateDocument>();
                    temp.Add(document);
                    versionDuplicates(temp, true);
                    Documents.Remove(document);
                    continue;
                }
                #endregion
            }
                
           #region Duplicates
           // DocClass document = verifyDuplicateClass(Document, businessRules);
            if (Documents != null)
                return verifyAction(Documents);
            else
            {
                Service.sendLog("La clase documental " + /*ID+  */ " no esta configurada en las reglas del negocio", Service.errorType.Error_Message);
                return false;
            }
            #endregion

        }


        #region verify CLASS in Business Rules

        private Incosistence verifyInconsistencies(duplicateDocument doc/*SqlDataReader reader*/, DuplicateService businessRules)
        {
            if (doc != null)
            {
                    Incosistence inconsistence = businessRules.getIncosistence(doc.getValue("CLASS"));
                    if (inconsistence == null)
                        return null;


                    foreach (IndexField field in inconsistence.Fields)
                    {
                        if (String.IsNullOrEmpty(doc.getValue(field.Name)))//el campo requerido no puede ser null ni en blanco                                               
                            return inconsistence;//se retorna la inconsistencia para q sea procesada (campo requerido en blanco)

                    }
                return null;
            }
            else
                return null;
        }

        private DocClassExc verifyException(duplicateDocument doc/*SqlDataReader reader*/, DuplicateService businessRules)
        {
            if (doc != null)
            {
               return businessRules.getException(doc.getValue("CLASS"), doc.getValue("OBJECT_NAME")); 
            }
            else
                return null;
        }

        private DocClass verifyDuplicateClass(duplicateDocument Document/*SqlDataReader reader*/, DuplicateService businessRules)
        {
            if (Document != null)
                return businessRules.getDuplicateClass(Document.getValue("CLASS"));  //en lab Unisys
            //return businessRules.getDuplicateClass(Document.getValue("CLASS"),Document.getValue("UNI_DOC"));  //en ambiente BCR
            else
                return null;
        }

        #endregion

        #region Actions
       

        //auxiliar method
        private string[] sortArray(string[] array)
        {
            array = array.Distinct().ToArray();
            Array.Sort(array);
            return array;
        }

        #region verifyAction
        /*
         * Verificar Lista de Documentos duplicados
         * Verificar rechazados
         * Verificar incosistencia de documento
         * Verficicar exception
         */ 
        private bool verifyAction( List<duplicateDocument> Documents/*SqlDataReader reader*/)
        {

            //Service.sendLog("Procesando documento [" + Document.getIDValue() + "], verificando duplicados", Service.errorType.Information_Message);
            bool processState = true;//bandera q indica el estado del proceso
            List<duplicateDocument> batch = new List<duplicateDocument>();
           
            foreach(duplicateDocument doc in Documents)
            {
                Service.sendLog("Documento con Object ID: [" + doc.getIDValue() + "] y Object_Class: [" + doc.getValue("OBJECT_CLASS") +"] fue considerado como DUPLICADO.", Service.errorType.Information_Message);

                if (doc.getValue("ORD_VENCE") != "1")
                {
                    batch.Add(doc);

                }
                else
                {
                    if (batch.Count > 0)
                    { 
                        versionDuplicates(batch,!(existDateNull(batch)));
                        batch.Clear();
                    }
                    batch.Add(doc);
                }
            }

            if (batch.Count > 0)
            { versionDuplicates(batch, !(existDateNull(batch)));
                }
            #endregion
            return true;
        }

        #endregion

            
        #region Actions Slave



        private string getAllDuplicateFields(List<string>list)
        {
            string result = "";
            string[] x = list.ToArray().Distinct().ToArray();
            foreach (string str in x)
            {
                result += "And C." + str + " = A." + str +" ";
            }
            return result;
        }

        public List< duplicateDocument> convertReaderToList(SqlDataReader reader)
        {
            List< duplicateDocument> documentsList = new List< duplicateDocument>();
            // int i = 0;
            while (reader.Read())
            {

                 duplicateDocument document = new  duplicateDocument();
                document.Fields = new List< IndexField>();
                try
                {
                    int cont = 0;

                    while (true)
                    {
                         IndexField field = new  IndexField();
                        field.Name = reader.GetName(cont);//en caso de llegar a la ulima columna envia excepcion de index out of...                        
                        field.Value = reader.GetSqlValue(cont).ToString();
                        cont++;
                        document.Fields.Add(field);
                    }
                }
                catch (Exception e) {}
                finally
                {
                    documentsList.Add(document);//agregar el documento a la lista
                }
            }
            return documentsList;
        }

        private bool existDateNull(List< duplicateDocument> duplicates)//retorna true si existe null en el campo VENCE
        {
            foreach (duplicateDocument document in duplicates)
            {
                string vence = document.getVENCEValue();
                if (String.IsNullOrEmpty(vence) || (vence.ToUpper().Equals("NULL")))//encuentra un documento con vence en blanco o null
                    return true;
            }
            return false;
        }

        private List<duplicateDocument> sort(int tamano, List< duplicateDocument> izquierda, List< duplicateDocument> derecha)
        {
            int i = 0, j = 0;
            DateTime date1, date2;
            List< duplicateDocument> sortedList = new List<duplicateDocument>();
            for (int k = 0; k < tamano; k++)
            {


                if (i >= izquierda.Count)
                { sortedList.Add(derecha[j]); j++; continue; }
                else
                { date1 = Convert.ToDateTime(izquierda[i].getVENCEValue()); }

                if (j >= derecha.Count)
                { sortedList.Add(izquierda[i]); i++; continue; }
                else
                { date2 = Convert.ToDateTime(derecha[j].getVENCEValue()); }

                if (DateTime.Compare(date1, date2) < 0)//agrega a la lista la fecha menor
                { sortedList.Add(izquierda[i]); i++; }
                else
                { sortedList.Add(derecha[j]); j++; }

            }
            return sortedList;
        }

        private List< duplicateDocument> reOrganizeData(List< duplicateDocument> duplicates)
        {

            if (duplicates.Count <= 1)
                return duplicates;
            else
            {
                int mitad = (duplicates.Count) / 2;
                List< duplicateDocument> der;


                if (((duplicates.Count) % 2) == 0)
                    der = duplicates.GetRange(mitad, mitad);
                else
                    der = duplicates.GetRange(mitad, mitad + 1);

                List< duplicateDocument> izq = duplicates.GetRange(0, mitad);


                return sort(duplicates.Count, reOrganizeData(izq), reOrganizeData(der));
            }
        }
        
        private string getAllDuplicateFields(duplicateDocument Document/*SqlDataReader reader*/,  DocClass doc)
        {
            string result = "";
            foreach ( IndexField field in doc.Fields)
            {
                result += "AND " + field.Name + " = '" + Document.getValue(field.Name) + "' ";
            }
            return result;
        }

        public bool versionDuplicates(List<duplicateDocument> Documents/*SqlDataReader queue*/, bool VersionVence)
        {
          
           
            SqlDataClass queryToDataBase = new SqlDataClass();
            //abrirConexion. 
   
            queryToDataBase.OpenConnection();

            int ultimo = 1;
            foreach (duplicateDocument dupli in Documents)
            {

                if (VersionVence)
                {
                    if (ultimo == Documents.Count)
                        queryToDataBase.SQLUpdate(dupli.getIDValue(), dupli.getValue("ORD_VENCE"), "0", false);//versionamiento sin buscar duplicados
                    else
                        queryToDataBase.SQLUpdate(dupli.getIDValue(), dupli.getValue("ORD_VENCE"), "1", false);//versionamiento sin buscar duplicados
                }
                else
                {
                    if (ultimo == Documents.Count)
                        queryToDataBase.SQLUpdate(dupli.getIDValue(), dupli.getValue("ORD_FECHA_REGISTRO"), "0", false);//versionamiento sin buscar duplicados
                    else
                        queryToDataBase.SQLUpdate(dupli.getIDValue(), dupli.getValue("ORD_FECHA_REGISTRO"), "1", false);//versionamiento sin buscar duplicados
                }
                ultimo++;
            }

            queryToDataBase.CloseConnection();
            return true;
            
        }

        public bool executeQuery() 
        {
            foreach(DocClass clases in bussinessRules.DocClassList)
            {
                return true;
            }
            return false;
        }

        #endregion



    }

}
